namespace Fftw
{
    using System;
    using System.Runtime.InteropServices;
    
    public class PlanComplexToReal3D : Plan
    {
        [DllImport ("libfftw3")]
        private static extern IntPtr fftw_plan_dft_c2r_3d(int nx, int ny, int nz, Complex[] in_data, double[] out_data, uint flags);
        
        [DllImport ("libfftw3")]
        private static extern void fftw_destroy_plan(IntPtr plan);
        
        private int n, nx, ny, nz;
        private double[] real_out;
        
        public PlanComplexToReal3D(int nx, int ny, int nz, Complex[] in_data, uint flags)
        {
            this.in_data = in_data;
            this.flags = flags;
            this.raw = IntPtr.Zero;
            this.nx = nx;
            this.ny = ny;
            this.nz = nz;
            this.n = nx * ny * nz;
            
            // in_data must be at least nx * ny * (nz/2 + 1)
            int ncomplex = nx * ny * (nz/2 + 1);
            if (in_data.Length < ncomplex)
                throw new FftwException(String.Format("Complex input data (length = {0}) is not large enough for a {1} X {2} X {3} DFT", in_data.Length, nx, ny, nz));
            
            out_data = null;
            real_out = new double[n];
            
            CreatePlan();
        }
        
        ~PlanComplexToReal3D()
        {
            fftw_destroy_plan(raw);
        }
        
        public double[] RealOutput
        {
            get { return real_out; }
        }
        
        protected override void CreatePlan()
        {
            raw = fftw_plan_dft_c2r_3d(nx, ny, nz, in_data, real_out, flags);
        }
    }
}
